use crate::life::Life;
use crate::map::Map;

#[derive(Clone)]
pub struct Population {
    lives: Vec<Life>,
    map: Map,
    pn: u32,
    pm: f64,
    pc: f64,
}

impl Population {
    pub fn new(map: Map, pn: u32, pm: f64, pc: f64) -> Population {
        let mut lives = Vec::new();
        for _i in 0..pn {
            lives.push(Life::new(map.gen_path()));
        }

        Population {
            lives,
            map,
            pn,
            pm,
            pc,
        }
    }
    pub fn iterator(&mut self) -> Option<&Life> {
        log::debug!("新一轮迭代");
        self.add_random();
        self.crosswave();
        self.selection();
        self.add_random();
        self.lives.get(0)
    }
    fn add_random(&mut self) {
        while self.lives.len() < self.pn as usize {
            self.lives.push(Life::new(self.map.gen_path()));
        }
    }
    fn crosswave(&mut self) {
        use rand::Rng;

        let len = self.lives.len();
        let mut wait_add = Vec::new();
        let mut rng = rand::thread_rng();

        for i in 0..len {
            for j in 0..len {
                if i == j {
                    continue;
                }

                let p: f64 = rng.gen();

                if p <= self.pc {
                    wait_add.push(&self.lives[i] + &self.lives[j]);
                }
            }
        }

        self.lives.clear();

        for mut life in wait_add {
            let p: f64 = rng.gen();

            if p <= self.pm {
                life.mutation();
            }
            self.lives.push(life);
        }
    }
    fn selection(&mut self) {
        self.lives
            .sort_by(|a, b| a.fitness().partial_cmp(&b.fitness()).unwrap());
        while self.lives.len() > self.pn as usize {
            self.lives.pop();
        }
    }
}
